package com.lcy.struct.bTreePlus.disk.recovery.undo;

import com.lcy.struct.bTreePlus.disk.constants.BPlusPublicConstants;
import com.lcy.struct.bTreePlus.disk.file.FileUtil;
import lombok.SneakyThrows;

import java.nio.channels.FileChannel;
import java.util.Arrays;

/**
 * @author lucongyang
 * @date Created in  9:55
 * @description
 */
class CommitUndo {

    private CommitUndo() {
    }

    static CommitUndo getInstance() {
        return Singleton.INSTANCE;
    }

    /**
     * 事务成功执行，提交事务
     *
     * @param transactionId 事务id
     */
    @SneakyThrows
    void commit(long transactionId) {
        Long position = UndoCenter.getInstance().transactionIdUndoStartPositionMap.get(transactionId);
        if (position != null) {
            byte[] undoStartStrBytes = BPlusPublicConstants.UNDO_START_STR.getBytes();
            byte[] undoEndCommitStrBytes = BPlusPublicConstants.UNDO_END_COMMIT_STR.getBytes();
            int size = undoStartStrBytes.length + BPlusPublicConstants.MAX_TRANSACTION_ID_LENGTH + undoEndCommitStrBytes.length;
            FileChannel channel = UndoCenter.getInstance().getUndoChannel();
            long undoEndPosition = UndoCenter.getInstance().getUndoEndPosition();
            int startPosition = BPlusPublicConstants.HEAD_SIZE;
            while (startPosition < undoEndPosition) {
                byte[] bytes = FileUtil.getInstance().read(startPosition, size, channel);
                int from = undoStartStrBytes.length + BPlusPublicConstants.MAX_TRANSACTION_ID_LENGTH;
                byte[] commit = Arrays.copyOfRange(bytes, from, bytes.length);
                String s = new String(bytes);
                if (s.startsWith(BPlusPublicConstants.UNDO_START_STR) &&
                        !BPlusPublicConstants.UNDO_END_COMMIT_STR.equals(new String(commit))) {
                    FileUtil.getInstance().straightRewrite(channel, startPosition + from, undoEndCommitStrBytes.length, true, undoEndCommitStrBytes);
                    break;
                }
                startPosition += BPlusPublicConstants.UNDO_PAGE_SIZE;
            }
        }
        UndoCenter.getInstance().transactionIdUndoStartPositionMap.remove(transactionId);
        UndoCenter.getInstance().transactionIdUndoStrListMap.remove(transactionId);
    }

    private static class Singleton {
        private static final CommitUndo INSTANCE = new CommitUndo();
    }
}
